#include "datacenter.h"

namespace model {

DataCenter* DataCenter::instance = nullptr;

DataCenter *DataCenter::getInstance()
{
    if(instance == nullptr)
    {
        instance = new DataCenter();

    }
    return instance;
}

inline DataCenter::~DataCenter()
{
    delete myself;
    delete chatSessionList;
    delete friendList;
    delete applyList;
    delete recentMessages;
    delete memberList;
    delete unReadMessagesCount;
    delete searchUserResult;
    delete searchMessageResult;
}

QString DataCenter::getLoginSessionId()
{
    return loginSessionId;
}

inline DataCenter::DataCenter() :netClient(this)
{

    //对三个hash进行实例化
    recentMessages = new QHash<QString,QList<Message>>();
    memberList = new QHash<QString, QList<UserInfo>>();
    unReadMessagesCount = new QHash<QString, int>();

    //从数据文件中加载数据
    loadDataFile();
}

inline void DataCenter::initDataFile()
{
    //如果没有file则创建
    QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/ChatClient.json";

    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        LOG() << "Cannot open file:" << file.errorString() << filePath;
        return;
    }
    // 写⼊初始内容
    QString data = "{\n\n}";
    file.write(data.toUtf8());
    file.close();
}

inline void DataCenter::saveDataFile()
{
    QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/ChatClient.json";
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        LOG() << "Cannot open file:" << file.errorString() << filePath;
        return;
    }
    //写入数据
    QJsonObject jsonObject;
    //写入登录会话id
    jsonObject["loginSessionId"] = loginSessionId;
    //写入未读消息
    QJsonObject jsonUnread;

    for(auto it = unReadMessagesCount->begin();it != unReadMessagesCount->end();++it)
    {
        jsonUnread[it.key()] = it.value();
    }

    jsonObject["unread"] = jsonUnread;

    //写入字符串
    QJsonDocument jsonDocument(jsonObject);
    QString s = jsonDocument.toJson();
    file.write(s.toUtf8());
    file.close();
}

inline void DataCenter::loadDataFile()
{
    QString basePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
    QString filePath = basePath + "/ChatClient.json";

    //如果没有basePath则创建
    QDir dir;
    if(!dir.exists(basePath)) dir.mkpath(basePath);

    //如果没有file则创建
    QFileInfo fileInfo(filePath);
    if(!fileInfo.exists()) initDataFile();

    //打开file
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        LOG() << "Cannot open file:" << file.errorString() << filePath;
        return;
    }
    //读取文件二进制数据
    QJsonDocument jsonDocument = QJsonDocument::fromJson(file.readAll());
    //如果文件为空则直接return
    if(jsonDocument.isNull())
    {
        LOG() << "Invalid JSON format";
        return;
    }
    QJsonObject jsonObject = jsonDocument.object();

    //读取登录会话id
    loginSessionId = jsonObject["loginSessionId"].toString();

    //读取未读消息, 读取前先清空目前的未读消息列表
    unReadMessagesCount->clear();

    QJsonObject jsonUnread = jsonObject["unread"].toObject();

    for(auto it = jsonUnread.begin();it != jsonUnread.end();++it)
    {
        (*unReadMessagesCount)[it.key()] = it.value().toInt();
    }

    //检查读取到的loginSessionId是否为空
    if(loginSessionId == "")
    {
        LOG() << "loginSessionId 为空";
        return;
    }
    file.close();
}
///////////////////////////////////////////////////////////////////////////////////////
/// 网络数据相关
///////////////////////////////////////////////////////////////////////////////////////
///个人信息
void DataCenter::getMyselfAsync()
{
    netClient.getMyself(loginSessionId);
}

UserInfo *DataCenter::getMyself()
{
    return myself;
}

void DataCenter::resetMyself(std::shared_ptr<bite_im::GetUserInfoRsp> resp)
{
    if(myself == nullptr)
    {
        myself = new UserInfo();
    }

    myself->load(resp->userInfo());
}
///好友列表
void DataCenter::getFriendListAsync()
{
    netClient.getFriendList(loginSessionId);
}

QList<UserInfo> *DataCenter::getFriendList()
{
    return friendList;
}

void DataCenter::resetFriendList(std::shared_ptr<bite_im::GetFriendListRsp> resp)
{
    if(friendList == nullptr)
    {
        friendList = new QList<UserInfo>();
    }

    friendList->clear();

    const QList<bite_im::UserInfo>& friendListPB = resp->friendList();
    for (auto& f : friendListPB) {
        UserInfo userInfo;
        userInfo.load(f);
        friendList->push_back(userInfo);
    }

}
///消息列表
void DataCenter::getChatSessionListAsync()
{
    netClient.getChatSessionList(loginSessionId);
}

QList<ChatSessionInfo> *DataCenter::getChatSessionList()
{
    return chatSessionList;
}

void DataCenter::resetChatSessionList(std::shared_ptr<bite_im::GetChatSessionListRsp> resp)
{
    if(chatSessionList == nullptr)
    {
        chatSessionList = new QList<ChatSessionInfo>();
    }

    chatSessionList->clear();

    const QList<bite_im::ChatSessionInfo>& chatSessionListPB = resp->chatSessionInfoList();
    for(auto& f : chatSessionListPB)
    {
        ChatSessionInfo chatSessionInfo;
        chatSessionInfo.load(f);
        chatSessionList->push_back(chatSessionInfo);
    }
}
///好友申请列表
void DataCenter::getApplyListAsync()
{
    netClient.getApplyList(loginSessionId);
}

QList<UserInfo> *DataCenter::getApplyList()
{
    return applyList;
}

void DataCenter::resetApplyList(std::shared_ptr<bite_im::GetPendingFriendEventListRsp> resp)
{
    if(applyList == nullptr)
    {
        applyList = new QList<UserInfo>();
    }

    applyList->clear();

    const QList<bite_im::FriendEvent>& applyListPB = resp->event();
    for(auto& f : applyListPB)
    {
        UserInfo userInfo;
        userInfo.load(f.sender());
        applyList->push_back(userInfo);
    }
}

void DataCenter::getRecentMessagesAsync(const QString &chatSessionId, bool updateUI)
{
    netClient.getRecentMessages(loginSessionId,chatSessionId,updateUI);
}

QList<Message> *DataCenter::getRecentMessages(const QString &chatSessionId)
{
    if(recentMessages->contains(chatSessionId)) return &(*recentMessages)[chatSessionId];
    else return nullptr;
}

void DataCenter::resetRecentMessages(const QString &chatSessionId, std::shared_ptr<bite_im::GetRecentMsgRsp> resp)
{
    QList<Message>& recentMessagesList = (*recentMessages)[chatSessionId];

    recentMessagesList.clear();

    //添加元素
    const QList<bite_im::MessageInfo>& recentMessagesListPB = resp->msgList();
    for(auto& f : recentMessagesListPB)
    {
        model::Message message;
        message.load(f);
        recentMessagesList.push_back(message);
    }
}

void DataCenter::sendTextMessageAsync(const QString &chatSessionId, const QByteArray &content)
{
    netClient.sendMessage(loginSessionId, chatSessionId,content,model::MessageType::TEXT_TYPE,"");
}

void DataCenter::addMessage(const Message &message)
{
    QList<Message>& messageList = (*recentMessages)[currentChatSessionId];
    messageList.push_back(message);
}

void DataCenter::addUnread(const QString &chatSessionId)
{
    ++(*unReadMessagesCount)[chatSessionId];
    saveDataFile();
}

int DataCenter::getUnread(const QString &chatSessionId)
{
    return (*unReadMessagesCount)[chatSessionId];
}

void DataCenter::clearUnread(const QString &chatSessionId)
{
    (*unReadMessagesCount)[chatSessionId] = 0;
    saveDataFile();
}

void DataCenter::changeNicknameAsync(const QString &nickname)
{
    netClient.changeNickname(loginSessionId,nickname);
}

void DataCenter::resetNickname(const QString &nickname)
{
    if(myself == nullptr)
    {
        LOG() << "DataCenter::resetNickname 失败, 错误原因: myself 为空指针";
        return;
    }
    myself->userName = nickname;
}

void DataCenter::changeDescriptionAsync(const QString &description)
{
    netClient.changeDescription(loginSessionId,description);
}

void DataCenter::resetDescription(const QString &description)
{
    if(myself == nullptr)
    {
        LOG() << "DataCenter::resetDescription 失败, 错误原因: myself 为空指针";
        return;
    }
    myself->userSignature = description;
}

void DataCenter::getVerifyCodeAsync(const QString &phone)
{
    netClient.getVerifyCode(phone);
}

QString DataCenter::getVerifyCodeId()
{
    return phoneVerifyCodeId;
}

void DataCenter::resetVerifyCodeId(std::shared_ptr<bite_im::PhoneVerifyCodeRsp> resp)
{
    phoneVerifyCodeId = resp->verifyCodeId();
}

void DataCenter::changePhoneAsync(const QString &phone, const QString &verifyCodeId, const QString &verifyCode)
{
    netClient.changePhone(loginSessionId,phone,verifyCodeId,verifyCode);
}

void DataCenter::resetPhone(const QString &phone)
{
    myself->userPhone = phone;
}

void DataCenter::changeAvatarAsync(const QByteArray &avatar)
{
    netClient.changeAvatar(loginSessionId,avatar);
}

void DataCenter::resetAvatar(const QByteArray &avatar)
{
    myself->userIcon = makeIcon(avatar);
}

void DataCenter::deleteFriendAsync(const QString &userId)
{
    netClient.deleteFriend(loginSessionId,userId);
}

void DataCenter::removeFriend(const QString &userId)
{
    if(friendList == nullptr || chatSessionList == nullptr)
    {
        LOG() << "DataCenter::removeFriend 失败, 原因: 好友列表和会话列表存在未实例化的空指针情况";
        return;
    }

    //调用removeif函数实现好友列表删除
    friendList->removeIf([=](const UserInfo& info){return userId == info.userId; });

    //调用removeif函数实现会话列表删除
    chatSessionList->removeIf([=](const ChatSessionInfo& info){
        //群聊会话不受影响
        if(info.SessionUserId == "") return false;
        //单聊会话中,非匹配会话不受影响
        else if(info.SessionUserId != userId) return false;
        //匹配会话必定会被删除, 只是后续操作不同: 如果匹配会话恰好是选中会话, 那么需要清空右侧消息展示区域, 否则不需要操作
        else
        {
            //选中会话, 需要额外清理消息展示区域
            if(info.SessionId == currentChatSessionId)
            {
                emit DataCenter::clearCurrentSession();
            }
            return true;
        }
    });
}

void DataCenter::addFriendApplyAsync(const QString &userId)
{
    netClient.addFriendApply(loginSessionId,userId);
}

void DataCenter::acceptFriendApplyAsync(const QString &userId)
{
    netClient.acceptFriendApply(loginSessionId,userId);
}

UserInfo DataCenter::removeFromApplyList(const QString &userId)
{
    if(applyList == nullptr) return UserInfo();

    for(int i = 0; i < applyList->size();++i)
    {
        if(applyList->at(i).userId == userId)
        {
            UserInfo ret = applyList->at(i);
            applyList->removeAt(i);
            return ret;
        }
    }

    return UserInfo();
}

void DataCenter::rejectFriendApplyAsync(const QString &userId)
{
    netClient.rejectFriendApply(loginSessionId,userId);
}

void DataCenter::createGroupChatSessionAsync(const QList<QString> &list)
{
    netClient.createGroupChatSession(loginSessionId,list);
}

void DataCenter::getMemberListAsync(const QString &chatSessionId)
{
    netClient.getMemberList(loginSessionId,chatSessionId);
}

QList<UserInfo> *DataCenter::getMemberList(const QString &chatSessionId)
{
    return &(*memberList)[chatSessionId];
}

void DataCenter::resetMemberList(const QString &chatSessionId, const QList<bite_im::UserInfo> &memberList)
{
    // if(this->memberList == nullptr || !memberList.contains(findChatSessionById(chatSessionId)))
    // {
    //     LOG() <<"DataCenter::resetMemberList 错误 ! 原因: memberList为空 或 找不到对应chatSessionId! ";
    //     return;
    // }
    auto list = (*this->memberList)[chatSessionId];
    list.clear();

    for(auto& f : memberList)
    {
        UserInfo userInfo;
        userInfo.load(f);
        list.push_back(userInfo);
    }

}

void DataCenter::searchUserAsync(const QString& searchKey)
{
    netClient.searchUser(loginSessionId,searchKey);
}

QList<UserInfo> *DataCenter::getSearchFriendList()
{
    return searchUserResult;
}

void DataCenter::resetSearchUserResult(const QList<bite_im::UserInfo> &userInfoList)
{
    if(searchUserResult == nullptr)
    {
        searchUserResult = new QList<UserInfo>();
    }

    searchUserResult->clear();

    for(auto& f : userInfoList)
    {
        UserInfo userInfo;
        userInfo.load(f);
        searchUserResult->push_back(userInfo);
    }
}

void DataCenter::searchMessageBySearchKeyAsync(const QString &searchKey)
{
    netClient.searchMessageBySearchKey(loginSessionId,currentChatSessionId,searchKey);
}

QList<Message> *DataCenter::getSearchMessageResult()
{
    return searchMessageResult;
}

void DataCenter::resetSearchMessageResult(const QList<bite_im::MessageInfo>& messageList)
{
    if(searchMessageResult == nullptr)
    {
        searchMessageResult = new QList<Message>();
    }

    searchMessageResult->clear();

    for(auto& f : messageList)
    {
        Message msg;
        msg.load(f);
        searchMessageResult->push_back(msg);
    }
}

void DataCenter::searchMessageByTimeAsync(const QDateTime &time1, const QDateTime &time2)
{
    netClient.searchMessageByTime(loginSessionId,currentChatSessionId,time1,time2);
}

void DataCenter::userLoginAsync(const QString &username, const QString &password)
{
    netClient.userLogin(username,password);
}

void DataCenter::resetLoginSessionId(const QString &loginSessionId)
{

}

void DataCenter::userRegisterAsync(const QString &username, const QString &password)
{
    netClient.userRegister(username,password);
}

void DataCenter::initWebsocket()
{
    netClient.initWebsocket();
}

void DataCenter::phoneLoginAsync(const QString &phone, const QString &verifyCode)
{
    netClient.phoneLogin(phone, verifyCode);
}

void DataCenter::phoneRegisterAsync(const QString &phone, const QString &verifyCode)
{
    netClient.phoneRegister(phone, verifyCode);
}

void DataCenter::sendImageMessageAsync(const QString &chatSessionId, const QByteArray &content)
{
    netClient.sendMessage(loginSessionId,chatSessionId,content,model::MessageType::IMAGE_TYPE,"");
}

void DataCenter::sendFileMessageAsync(const QString &chatSessionId, const QByteArray &content, const QString &fileName)
{
    netClient.sendMessage(loginSessionId,chatSessionId,content,model::MessageType::FILE_TYPE,fileName);
}

void DataCenter::sendSpeechMessageAsync(const QString &chatSessionId, const QByteArray &content)
{
    netClient.sendMessage(loginSessionId,chatSessionId,content,model::MessageType::SPEECH_TYPE,"");
}

void DataCenter::speechConvertTextAsync(const QString &fileId, const QByteArray &content)
{
    netClient.speechConvertText(loginSessionId,fileId,content);
}

void DataCenter::getSingleFileAsync(const QString &fileId)
{
    netClient.getSingleFile(loginSessionId,fileId);
}

ChatSessionInfo* DataCenter::findChatSessionById(const QString &chatSessionId)
{
    if(chatSessionList == nullptr)
        return nullptr;

    for(auto it = chatSessionList->begin(); it != chatSessionList->end();++it)
    {
        if(it->SessionId == chatSessionId) return it;
    }

    return nullptr;
}

ChatSessionInfo * DataCenter::findChatSessionByUserId(const QString &userId)
{
    if(chatSessionList == nullptr)
        return nullptr;

    for(auto it = chatSessionList->begin(); it != chatSessionList->end();++it)
    {
        if(it->SessionUserId == userId) return it;
    }

    return nullptr;
}

void DataCenter::topChatSessionInfo(const ChatSessionInfo &chatSessionInfo)
{
    if (chatSessionList == nullptr) {
        return;
    }

    // 1. 把这个元素从列表中找到
    auto it = chatSessionList->begin();
    for (; it != chatSessionList->end(); ++it) {
        if (it->SessionId == chatSessionInfo.SessionId) {
            break;
        }
    }

    if (it == chatSessionList->end()) {
        // 上面的循环没有找到匹配的元素, 直接返回. 正常来说, 不会走这个逻辑的.
        return;
    }

    // 2. 把这个元素备份一下, 然后删除
    ChatSessionInfo backup = chatSessionInfo;
    chatSessionList->erase(it);

    // 3. 把备份的元素, 插入到头部
    chatSessionList->push_front(backup);
}

void DataCenter::setCurrentChatSessionId(const QString &chatSessionId)
{
    currentChatSessionId = chatSessionId;
}

QString DataCenter::getCurrentChatSessionId()
{
    return currentChatSessionId;
}

UserInfo *DataCenter::findFriendById(const QString &userId)
{
    if(friendList == nullptr) return nullptr;

    for(auto& f : *friendList)
    {
        if(f.userId == userId) return &f;
    }

    return nullptr;
}
}













